import {install} from './install'
import {
  getHelpfulElement,
  isNullOrEmpty,
  isEmptyObject,
  mergeOption,
  checkOptions,
  getAllAttr,
  getStorage,
  delStorage,
  setStorage,
  getTime,
  getUuid,
  bigNumSub
} from './util/util'
const UUID_PREFIX = 'ALD';

import {BASEOPTIONS} from './util/config'

/**
 * 原生事件涉及到移除与绑定，所以缓存CallChainLog
 * */
// let _CallChainLog;
// 通用参数:登录流水、操作员手机号、地市、操作员工号
let commonAcData={};
export default class CallChainLog {
  /**
   * @param options 配置项
   * @param Vue 当前Vue实例， 主要目的是使用nextTick, 保证数据上报不影响页面展示效率
   * */
  constructor(options = {}, Vue = {}) {
    const newOptions = mergeOption(options, BASEOPTIONS);
    newOptions.logSwitchMap = options.logSwitchMap;
    if(!checkOptions(newOptions)){
      this.installed = false;
      return
    }
    
    this.installed = true;
    this._options = newOptions;
    this._vue_ = Vue;
    this._axios = options.axios;
    // _CallChainLog = this;
    //登录流水、操作员手机号、地市、操作员工号
    commonAcData = options.commonAcData;
    const cacheEventData = getStorage( this._options.cacheEventStorage);
    this._acData = isNullOrEmpty(cacheEventData) ? [] : JSON.parse(cacheEventData);
    delStorage(this._options.cacheEventStorage);

    this._inputCacheData = {};  //缓存输入框输入信息
    this._componentsTime = {};  //缓存组件加载时间
    this._lastRouterStr = '';   //防止路由重复采集
    this._userToken = '';       //关联后台token
    
    this._componentLoadCount = 0;   //保证所有组件渲染完成
    this._componentTimeCount = 0;   //保证所有组件渲染完成
    this._currentDom = '';//当前dom
    this._lastPage = '';//上一个页面
    this._curentPage = '';//当前页面
    this._pSpanid = '';//上一个页面的spanId

    this._init();
  }

  
  /**
   * 页面初始化
   * */
  _init() {

    /**
    * 点击事件代理初始化
    * */
    if (this._options.openClick) {
      this._initClickAc();
    }
    this.refreshTimeOutObj();//刷新定时器
  }


  /**
   *  混入vue生命周期 beforeCreate
   *  用来监控组件渲染性能
   *  @param Component 组件
   * */
  _mixinComponentsPerformanceStart(Component){
    const {$vnode = {}} = Component;
    const tag = $vnode.tag;
    //没有tag的组件不做采集，找不到唯一标识
    if(isNullOrEmpty(tag)){
      return;
    }

    Component.$_chain_bc_time = getTime().timeStamp;
    Component.$vueDataAc._componentTimeCount++;
  }

  /**
   *  混入vue生命周期 Mounted
   *  用来监控组件渲染性能
   *  @param Component 组件
   * */
  _mixinComponentsPerformanceEnd(Component){
    const createdTime = Component.$_chain_bc_time;
    const {$vnode = {}} = Component;
    const tag = $vnode.tag;

    //没有tag的组件不做采集，找不到唯一标识
    if(isNullOrEmpty(createdTime) || isNullOrEmpty(tag)){
      return;
    }

    const nowTime = getTime().timeStamp;
    const loadTime = parseInt(nowTime - createdTime);

    if(loadTime >= Component.$vueDataAc._options.maxComponentLoadTime){
      if(isNullOrEmpty(Component.$vueDataAc._componentsTime[tag])){
        Component.$vueDataAc._componentsTime[tag] = [];
      }
      Component.$vueDataAc._componentsTime[tag].push(loadTime);
    }

    const isLoaded = (--Component.$vueDataAc._componentTimeCount === 0);

    if(isLoaded && !isEmptyObject(Component.$vueDataAc._componentsTime)){
      // this._setAcData(Component.$vueDataAc._options.storeCompErr, {
      //   componentsTimes: Component.$vueDataAc._componentsTime
      // })
      Component.$vueDataAc._componentsTime = {};
    }
  }


  /**
   *  混入vue watch 用来监控路由变化
   * */
  _mixinRouterWatch(to = {}, from = {}, isVueRouter) {
    let toPath = '';
    let toParams = {};
    let fromPath = '';
    let formParams = {};
    let _lastRouterStr = '';
    if(isVueRouter){
      toPath =  to.path || to.name;
      toParams = isEmptyObject(to.params) ? to.query : to.params;
      fromPath = from.path || from.name;
      formParams = isEmptyObject(from.params) ? from.query : from.params;
      _lastRouterStr = this._lastRouterStr;
      // console.info(_lastRouterStr,`${toPath}`,'_lastRouterStr === `${toPath}`');
      if (_lastRouterStr === `${toPath}`) {
        return
      }
    }else{
      _lastRouterStr = getStorage(`_chain_${this._options.storePage}`) || ''
      toPath = window.location.href;
      toParams = { search: window.location.search }
      fromPath = _lastRouterStr;
      formParams = {}
    }

    //该情况认为是根页面渲染，留给页面级信息上报
    if (isVueRouter && (isNullOrEmpty(toPath) || isNullOrEmpty(fromPath))) {
      return;
    }
    toPath = toPath.substring(toPath.indexOf('#')+1);
    
    this._lastRouterStr = `${toPath}`;
    setStorage(`_chain_${this._options.storePage}`, `${toPath}`)
    
    // this._setAcData(this._options.storePage, {
    //   toPath,
    //   toParams,
    //   fromPath,
    //   formParams
    // })
  }

  /**
   *  初始化点击事件
   * */
  _initClickAc() {
    document.addEventListener("click", (e) => {
      const event = window.event || e;
      const target = event.srcElement ? event.srcElement : event.target;
      const helpfulElement = getHelpfulElement(target, this._options)
      if(!isNullOrEmpty(helpfulElement)){
        if(!this.lastTargetDom){//记录上次点击的dom
          this.lastTargetDom = helpfulElement;
        } else {
          this.lastTargetDom = this.currentTargetDom;
        }
        this.currentTargetDom = helpfulElement;//记录当前dom
        const {className, value, innerText,nodeName,innerHtml} = helpfulElement;

        if(this.lastTargetDom == this.currentTargetDom && (nodeName == 'INPUT' || nodeName == 'TEXTAREA')){
          return;//如果是重复点击同一个input输入框 就跳过
        }
        let spanTxt = value || innerText || innerHtml;
        spanTxt = spanTxt == void 0 ?'':'_'+spanTxt;
        let currentDom = nodeName + '.' + className + spanTxt;//当前dom
        this._currentDom =  this._setPageDom(target.getAttribute("data-url"),currentDom);//拼接当前页面

        //设置点击参数
        this._setAcData(this._options.storeClick, {
          dom: this._currentDom,
        })
      }
    });
  }

  

  /**
   * 数据采集存储, 包含数据格式化
   * options，当前采集的对象
   * */
  _setAcData(options, data) {
    if(!commonAcData.busiSeq){//有业务流水才采集点击事件
      return;
    }
    commonAcData.spanNode++;
    const _Ac = commonAcData || {};//公用参数
    
    let type = '';
    switch (options) {
      case this._options.storeClick: {//点击事件，获取当前点击的dom元素
          type = this._options.storeClick;
        }
        break;
      case this._options.storePage: {//页面切换
          type = this._options.storePage;
          const {toPath, fromPath} = data;
          this._lastPage = fromPath;//上一个页面
          this._curentPage = toPath;//当前页面
        }
        break;
      default:
        break;
    }
    //login_traceId、业务traceId、busitype（客户视图进入则加前缀csview_）、采集时间、imei、页面路径、dom元素、
    _Ac.type = type;//类型：页面切换、点击 
    _Ac.lastPage = this._lastPage;//上一个页面
    _Ac.curentPage = this._curentPage;//当前页面
    _Ac.pSpanid = this._pSpanid;//上一个页面的spanId 第一次应该为空
    _Ac.spanId = getUuid(UUID_PREFIX);//当前spanId
    _Ac.spanNode = commonAcData.spanNode;
    setStorage('pageSpanId',_Ac.spanId);
    
    _Ac.pageDom = this._currentDom;
    this._pSpanid = _Ac.spanId;//上一个页面的spanId
    let startTimeObj = (data&&data.startTime) || getTime();//开始时间
    let endTimeObj = getTime();//结束时间
    _Ac.startTime = startTimeObj.timeStr;//点击动作的开始时间
    _Ac.collectTime =  endTimeObj.timeStr;//采集时间
    _Ac.invokeTime = endTimeObj.timeStamp - startTimeObj.timeStamp;//调用时间
    _Ac.statusCode = data.statusCode || '0';
    _Ac.errorMsg = data.errorMsg || '';//错误信息
    //如果开关没开，则不上传到离线文件 
    let uploadFlg = this._options.logSwitchMap[_Ac.busiType];
    if(uploadFlg == '2'){//不采集
      return;
    }
    let dataLine = this.transferDataLine(_Ac);
    this._acData.push(dataLine);
    if (this._options.openReducer) {//开户节流
      //缓存到storage
      setStorage(this._options.cacheEventStorage, JSON.stringify(this._acData))
      if (!this._options.manualReport && this._options.sizeLimit && this._acData.length >= this._options.sizeLimit) {
        this.postAcData();
      }
    } else {
      this.postAcData();
    }
  }
  //组装每行的数据
  transferDataLine(_Ac){
    let arr = {
      "traceId": _Ac.busiSeq,//业务流水
      "pSpanid": _Ac.pSpanid,
      "spanId": _Ac.spanId,
      "spanNode":_Ac.spanNode,
      "spanName": _Ac.pageDom,//dom元素
      "startTime": _Ac.startTime,//开始时间
      "endTime": _Ac.collectTime,//结束时间 add at 20221031
      "invokeTime": _Ac.invokeTime,//耗时
      "attributes": {
        "statusCode": _Ac.statusCode,
        "operId": _Ac.operId,//操作员工号
        "telnum": _Ac.telnum,//用户手机号
        "imei": _Ac.imei,//imei
        "serverNum": _Ac.serverNum,//操作员手机号
        "busiType": _Ac.busiType,//业务类型=菜单编号
        "region": _Ac.region,//地市
        "podIp": "",
        "errorMsg":_Ac.errorMsg,//错误信息，前端点击无此节点内容，客户端回调有报错信息
        "loginId":_Ac.loginTraceId,//登录流水
      }
    }
    return arr;
  }
  //设置当前页面和当前dom元素
  _setPageDom(page,dom){
    let p = page || window.location.hash;

    if(~p.indexOf('#')){//hash路由模式，路径带#
      let startIdx = p.indexOf('#')+1;
      p = p.substring(startIdx);
      
      if(~p.indexOf('?')){
        p = p.substring(0, p.indexOf('?'));
      }
    }
    let val = p+'@'+dom;
    
    return val;	
  }
  //清除定时器
  clearTimeOutObj() {
    if(this.timeOutObj){//先判断定时器存在不
      this.timeOutObj = null;
    }
  }

  //刷新定时器
  refreshTimeOutObj() {
    this.clearTimeOutObj();//先清空定时器
    this.timeOutObj = setTimeout(()=>{
      this.postAcData();
    },this._options.timeThresholds);
  }

  /**
   *  数据上报, 可以根据实际场景进行上报优化：
   *  默认当事件触发就会自动上报，频率为一个事件1次上报
   *  如果频率过大，可以使用 openReducer， sizeLimit，manualReport进行节流
   * */
  postAcData() {
    if (isNullOrEmpty(this._acData) || this._acData.length === 0) {
      return;
    }
    this.clearTimeOutObj();
    //取日志队列的前countThresholds条，如果不足countThresholds，则会取全部
    let curLogArr = this._acData.splice(0,this._options.sizeLimit);
    
    console.dir(curLogArr);
    
    let param = {
        logContent:JSON.stringify(curLogArr),
        unLoadFlg:true//屏蔽加载圈
    }
    //接口上报
    this._axios.post(this._options.postUrl,param).then((res) => {
      /**
       * 上报完成，清空数据
       * */
      this.refreshTimeOutObj();//刷新定时器
      delStorage(this._options.cacheEventStorage)
    }).catch( e =>{
      console.error(e);
    });    
  }

  /**
   * 关联后台session
   * */
  setUserToken(value) {
    this._userToken = value;
  }
  //鉴权框的点击事件
  collectClick = (dom) => {
    if(dom){
      this._currentDom = this._setPageDom(null,dom);
       //设置点击参数
       this._setAcData(this._options.storeClick, {
          dom: dom,
      })
    }
  }
  //采集客户端回调信息
  collectClientCbInfo(dom,extraParam){
    if(dom){
      this._currentDom = this._setPageDom(null,dom);
      let param = {
        dom: dom,
      }
      Object.assign(param,extraParam);
      // console.info(param);
       //设置点击参数
      this._setAcData(this._options.storeClick,param)
    }
  }
}
//设置公共参数 业务traceId、busitype（菜单编号） 用户手机号、操作员手机号、地市、操作员工号
CallChainLog.setCommenData = (param)=>{
  if(param && typeof param == 'object'){
    Object.assign(commonAcData,param)
  }
}

//清除参数
CallChainLog.clearCommenData = (key)=>{
  if(commonAcData && commonAcData[key]){
    //清除commonAcData对象中key对应的属性
    delete commonAcData[key]
  }
}
//获取参数
CallChainLog.getCommenData = (key)=>{
  if(commonAcData && commonAcData[key]){
    //获取commonAcData对象中key对应的属性
    return commonAcData[key]
  }
}
CallChainLog.install = (Vue, options) => install(Vue, options, CallChainLog);
CallChainLog.version = '__VERSION__';